/*
 * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
 * Copyright (C) 2011 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "FrameLoaderClientCd.h"
#include <AuthenticationChallenge.h>
#include <Credential.h>

#include "DocumentLoader.h"
#include "FrameLoader.h"
#include "FrameNetworkingContextCd.h"
#include "FrameView.h"
#include "HTMLFormElement.h"
#include "MIMETypeRegistry.h"
#include "DOMImplementation.h"
#include "MainFrame.h"
#include "NotImplemented.h"
#include "Page.h"
#include "Settings.h"
#include "RenderTreeAsText.h"
#include "PluginDatabase.h"
#include "PolicyChecker.h"
#include "RenderWidget.h"
#include <ResourceHandle.h>
#include "ResourceLoader.h"
#include "Language.h"
//#include "WebKitVersion.h"
#include "WebView.h"
#include <wtf/text/StringConcatenate.h>
#include "WebKitLogging.h"

using namespace WebCore;

namespace WebKit {

FrameLoaderClientCd::FrameLoaderClientCd(WebView* view,WebCore::Frame*frame)
    : m_webView(view) , m_frame(nullptr) , m_pluginView(nullptr)
{
    m_frame=frame?frame:&view->page()->mainFrame();
    ASSERT(m_webView);
}

FrameLoaderClientCd::~FrameLoaderClientCd()
{
}

String FrameLoaderClientCd::userAgent(const URL&)
{
    DEPRECATED_DEFINE_STATIC_LOCAL(String, userAgentString, ());

    if (userAgentString.isNull()) {
        String webKitVersion = String::format("%d.%d", 1,0);//WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION);
        userAgentString = makeString("Mozilla/5.0 (", "windowsVersionForUAString()", ") AppleWebKit/", webKitVersion, " (KHTML, like Gecko) Mobile Safari/", webKitVersion);
    }

    return userAgentString;
}

PassRefPtr<DocumentLoader> FrameLoaderClientCd::createDocumentLoader(const WebCore::ResourceRequest& request, const SubstituteData& substituteData)
{
    return DocumentLoader::create(request, substituteData);
}

void FrameLoaderClientCd::committedLoad(DocumentLoader* loader, const char* data, int length)
{
    if (m_pluginView) {
        if (!m_hasSentResponseToPlugin) {
            m_pluginView->didReceiveResponse(loader->response());
            m_hasSentResponseToPlugin = true;
        }
        m_pluginView->didReceiveData(data, length);
    } else
        loader->commitData(data, length);
}

bool FrameLoaderClientCd::shouldUseCredentialStorage(DocumentLoader*, unsigned long)
{
    notImplemented();
    return false;
}

void FrameLoaderClientCd::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long, const AuthenticationChallenge&challenge)
{// (not completed)reference from fltk port
    LOG(FrameLoader,"FrameLoaderClientCd::%s",__func__);
    const String msg = challenge.protectionSpace().realm();
    challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);

    //Credential cred(username, password, CredentialPersistenceForSession);
    //challenge.authenticationClient()->receivedCredential(challenge, cred);
    //notImplemented();
}

void FrameLoaderClientCd::dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long, const AuthenticationChallenge&)
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchWillSendRequest(DocumentLoader*, unsigned long, WebCore::ResourceRequest&request, const WebCore::ResourceResponse&)
{
    WebCore::Page*page=m_webView->page();
    notImplemented();
    //LOG(FrameLoader,"FrameLoaderClientCd::dispatchWillSendRequest(%s)",request.url().string().utf8().data());
    request.addHTTPHeaderField(String("Accept-Language"), WebCore::defaultLanguage() + WTF::String(",en,*"));
    request.addHTTPHeaderField(String("Accept-Charset"), page->settings().defaultTextEncodingName() + WTF::String(",utf-8;q=0.7,*;q=0.3"));    
}

void FrameLoaderClientCd::assignIdentifierToInitialRequest(unsigned long, DocumentLoader*, const WebCore::ResourceRequest&)
{
    notImplemented();
}

void FrameLoaderClientCd::frameLoaderDestroyed()
{
    m_webView = 0;
    m_frame = 0;
    delete this;
}

void FrameLoaderClientCd::dispatchDidReceiveResponse(DocumentLoader*, unsigned long, const ResourceResponse& response)
{
    m_response = response;
}

void FrameLoaderClientCd::dispatchDecidePolicyForResponse(const WebCore::ResourceResponse& response, 
	const WebCore::ResourceRequest&, FramePolicyFunction policyFunction)
{
    if (canShowMIMEType(response.mimeType()))
        policyFunction(PolicyUse);
    else
        policyFunction(PolicyDownload);
}

void FrameLoaderClientCd::dispatchDecidePolicyForNewWindowAction(const NavigationAction&, 
    const WebCore::ResourceRequest&, PassRefPtr<FormState>, const String&, FramePolicyFunction policyFunction)
{
    policyFunction(PolicyUse);
}

void FrameLoaderClientCd::dispatchDecidePolicyForNavigationAction(const NavigationAction&, 
	const WebCore::ResourceRequest&, PassRefPtr<FormState>, FramePolicyFunction policyFunction)
{
    policyFunction(PolicyUse);
}

void FrameLoaderClientCd::dispatchWillSubmitForm(PassRefPtr<FormState>, FramePolicyFunction policyFunction)
{
    policyFunction(PolicyUse);
}

PassRefPtr<Widget> FrameLoaderClientCd::createPlugin(const IntSize& pluginSize, HTMLPlugInElement* element, const URL& url,
    const Vector<String>&paramNames, const Vector<String>&paramValues, const String&mimeType, bool loadManually)
{
    LOG(FrameLoader,"FrameLoaderClientCd::createPlugin(%s)",url.string().utf8().data());
#if 0	
    Vector<String> newParamNames = paramNames;
    Vector<String> newParamValues = paramValues;

    unsigned int i = 0;
    for (; i < newParamNames.size(); i++) {
        if (equalIgnoringCase(paramNames[i], "wmode"))
            break;
    }

    if (i == newParamNames.size()) {
        newParamNames.append("wmode");
        newParamValues.append("opaque");
    }

    if (!equalIgnoringCase(newParamValues[i], "opaque") &&
        !equalIgnoringCase(newParamValues[i], "transparent")) {
        newParamValues[i] = "opaque";
    }

    RefPtr<WebCore::PluginView> pluginView = WebCore::PluginView::create(m_frame, pluginSize, element, url, newParamNames, newParamValues, mimeType, loadManually);
    if (pluginView->status() == WebCore::PluginStatusLoadedSuccessfully)
        return pluginView;	
#endif    
    return nullptr;
}

PassRefPtr<Frame> FrameLoaderClientCd::createFrame(const URL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
                           const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)
{
    LOG(FrameLoader,"FrameLoaderClientCd::createFrame %s",url.string().utf8().data());
    WebCore::Frame*parent=m_frame;
    FrameLoaderClientCd* loader = new FrameLoaderClientCd(m_webView);
    RefPtr<WebCore::Frame> childFrame = WebCore::Frame::create(m_webView->page(), ownerElement, loader);
    loader->setFrame(childFrame.get());
    parent->tree().appendChild(childFrame);
    childFrame->tree().setName(name);
    childFrame->init();
    
    if(!childFrame->page())return nullptr;
    parent->loader().loadURLIntoChildFrame(url, referrer, childFrame.get());
    if (!childFrame->tree().parent())
        return 0;

    return childFrame.release();    
}

void FrameLoaderClientCd::redirectDataToPlugin(Widget* pluginWidget)
{
    m_pluginView = toPluginView(pluginWidget);
    if (pluginWidget)
        m_hasSentResponseToPlugin = false;
}

PassRefPtr<Widget> FrameLoaderClientCd::createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const URL&, const Vector<String>&, const Vector<String>&)
{
    notImplemented();
    return 0;
}

ObjectContentType FrameLoaderClientCd::objectContentType(const URL& url, const String& mimeType, bool shouldPreferPlugInsForImages)
{
    return FrameLoader::defaultObjectContentType(url, mimeType, shouldPreferPlugInsForImages);
}

String FrameLoaderClientCd::overrideMediaType() const
{
    notImplemented();
    return String();
}

void FrameLoaderClientCd::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld&)
{
    notImplemented();
}

void FrameLoaderClientCd::registerForIconNotification(bool)
{
    notImplemented();
}

void FrameLoaderClientCd::setMainFrameDocumentReady(bool)
{
    notImplemented();
}

bool FrameLoaderClientCd::hasWebView() const
{
    return true;
}

void FrameLoaderClientCd::dispatchDidFinishLoad()
{
    notImplemented();
}

void FrameLoaderClientCd::frameLoadCompleted()
{
    notImplemented();
}

void FrameLoaderClientCd::saveViewStateToItem(HistoryItem*)
{
    notImplemented();
}

void FrameLoaderClientCd::restoreViewState()
{
    notImplemented();
}

bool FrameLoaderClientCd::shouldGoToHistoryItem(HistoryItem* item) const
{
    return item;
}

void FrameLoaderClientCd::didDisplayInsecureContent()
{
    notImplemented();
}

void FrameLoaderClientCd::didRunInsecureContent(SecurityOrigin*, const URL&)
{
    notImplemented();
}

void FrameLoaderClientCd::didDetectXSS(const URL&, bool)
{
    notImplemented();
}

void FrameLoaderClientCd::makeRepresentation(DocumentLoader*)
{
    notImplemented();
}

void FrameLoaderClientCd::forceLayoutForNonHTML()
{
    notImplemented();
}

void FrameLoaderClientCd::setCopiesOnScroll()
{
    notImplemented();
}

void FrameLoaderClientCd::detachedFromParent2()
{
    notImplemented();
}

void FrameLoaderClientCd::detachedFromParent3()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidHandleOnloadEvents()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidReceiveServerRedirectForProvisionalLoad()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidCancelClientRedirect()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchWillPerformClientRedirect(const URL&url, double, double)
{
    LOG(FrameLoader,"FrameLoaderClientCd::dispatchWillPerformClientRedirect(%s)",url.string().utf8().data());
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidChangeLocationWithinPage()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidPushStateWithinPage()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidReplaceStateWithinPage()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidPopStateWithinPage()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchWillClose()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidReceiveIcon()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidStartProvisionalLoad()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidReceiveTitle(const StringWithDirection&title)
{
    notImplemented();
    /*if (m_frame == &m_page->mainFrame()){
        const wkeClientHandler* handler = m_webView->getClientHandler();
        if (handler && handler->onTitleChanged)
             handler->onTitleChanged(handler, (const wkeString)&title.string());
    }*/    
}

void FrameLoaderClientCd::dispatchDidChangeIcons(WebCore::IconType)
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidCommitLoad()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidFinishDocumentLoad()
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchDidLayout(LayoutMilestones)
{
    notImplemented();
}

void FrameLoaderClientCd::dispatchShow()
{
    LOG(FrameLoader,"FrameLoaderClientCd::dispatchShow");
    m_webView->invalidate();
    notImplemented();
}

void FrameLoaderClientCd::cancelPolicyCheck()
{
    notImplemented();
}

void FrameLoaderClientCd::revertToProvisionalState(DocumentLoader*)
{
    notImplemented();
}

void FrameLoaderClientCd::willChangeTitle(DocumentLoader*)
{
    notImplemented();
}

void FrameLoaderClientCd::didChangeTitle(DocumentLoader* documentLoader)
{
    setTitle(documentLoader->title(), documentLoader->url());
}

static bool CanHandleRequest(const WebCore::ResourceRequest& request)
{
    // Always handle "POST" in place
    if (equalIgnoringCase(request.httpMethod(), "POST"))
        return true;
    const WebCore::URL& requestUrl = request.url();
    const WTF::String& url = requestUrl.string();
    // Empty URLs should not be sent to Java
    if (url.isEmpty())
        return true;
    return true;
}

bool FrameLoaderClientCd::canHandleRequest(const WebCore::ResourceRequest&request) const
{
    bool canHandle = WebCore::equalIgnoringFragmentIdentifier(request.url(), m_frame->document()->url()) ||
            (request.url().protocol().startsWith("http", false) && m_frame->tree().parent()) ||
            CanHandleRequest(request);
    return canHandle;   
}

bool FrameLoaderClientCd::canShowMIMEType(const String& mimeType) const
{
    // FIXME: This looks like it has to do with whether or not a type can be
    // shown "internally" (i.e. inside the browser) regardless of whether
    // or not the browser is doing the rendering, e.g. a full page plugin.
    return MIMETypeRegistry::isSupportedImageResourceMIMEType(mimeType) ||
            MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType) ||
            MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) ||
            (m_frame && m_frame->settings().arePluginsEnabled()
                    && PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType)) ||
            (DOMImplementation::isTextMIMEType(mimeType) &&!mimeType.startsWith("text/vnd")) ||
            DOMImplementation::isXMLMIMEType(mimeType);
}

bool FrameLoaderClientCd::canShowMIMETypeAsHTML(const String&type) const
{
    notImplemented();
    LOG(FrameLoader,"FrameLoaderClientCd::canShowMIMETypeAsHTML %s",type.utf8().data());
    return false;
}

bool FrameLoaderClientCd::representationExistsForURLScheme(const String&) const
{
    notImplemented();
    return false;
}

String FrameLoaderClientCd::generatedMIMETypeForURLScheme(const String&URLScheme) const
{
    String mimetype("x-apple-web-kit/");
    mimetype.append(URLScheme.lower());
    return mimetype;
}

void FrameLoaderClientCd::finishedLoading(DocumentLoader*)
{
    if (!m_pluginView)
        return;

    m_pluginView->didFinishLoading();
    m_pluginView = 0;
    m_hasSentResponseToPlugin = false;
}

void FrameLoaderClientCd::provisionalLoadStarted()
{
    notImplemented();
}

void FrameLoaderClientCd::didFinishLoad()
{
    notImplemented();
}

void FrameLoaderClientCd::prepareForDataSourceReplacement()
{
    notImplemented();
}

void FrameLoaderClientCd::setTitle(const StringWithDirection&title, const URL&)
{
    //LOG(FrameLoader,"FrameLoaderClientCd::setTitle:%s",title.string().utf8().data());
}

void FrameLoaderClientCd::dispatchDidReceiveContentLength(DocumentLoader*loader, unsigned long identifier, int dataLength)
{
    //LOG_VERBOSE(FrameLoader,"loader=%p,identifier=%d dataLength=%d",dataLength);
}

void FrameLoaderClientCd::dispatchDidFinishLoading(DocumentLoader*loader, unsigned long identifier)
{
    //notImplemented();
    //static_cast<WebKit::DocumentLoader*>(loader)->decreaseLoadCount(identifier);
    //if (view->priv->resourceStateChanged)
    //    view->priv->resourceStateChanged(identifier, true);
}

void FrameLoaderClientCd::dispatchDidFailLoading(DocumentLoader*loader, unsigned long identifier, const ResourceError&)
{
    LOG(FrameLoader,"loader=%p",loader);
    //static_cast<WebKit::DocumentLoader*>(loader)->decreaseLoadCount(identifier);
    notImplemented();
}

bool FrameLoaderClientCd::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*loader, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, int length)
{
    //LOG(FrameLoader,"FrameLoaderClientCd::%s ldoader=%p,len=%d",__func__,loader,length);
    return false;
}

void FrameLoaderClientCd::dispatchDidFailProvisionalLoad(const ResourceError& error)
{
    dispatchDidFailLoad(error);
}

void FrameLoaderClientCd::dispatchDidFailLoad(const ResourceError&)
{
    notImplemented();
}

void FrameLoaderClientCd::convertMainResourceLoadToDownload(WebCore::DocumentLoader*dl, const WebCore::ResourceRequest&req, const WebCore::ResourceResponse&resp)
{
    LOG(FrameLoader,"FrameLoaderClientCd::%s dl=%p req=%s resp=%s",__func__,dl,req.url().string().utf8().data(),resp.url().string().utf8().data());
    notImplemented();
    dl->mainResourceLoader()->handle()->setDefersLoading(true);
    /*m_webView->download(req.url().string().utf8().data(), resp.suggestedFilename().isEmpty() ?
           req.url().lastPathComponent().utf8().data() :
           resp.suggestedFilename().utf8().data(), &req);*/
    
}

ResourceError FrameLoaderClientCd::cancelledError(const WebCore::ResourceRequest&request)
{
    return  ResourceError(String(), InternalErrorCancelled, request.url(), String());
}

ResourceError FrameLoaderClientCd::blockedError(const WebCore::ResourceRequest&request)
{
    return  ResourceError(String(), InternalErrorCannotShowUrl, request.url(), String());
}

ResourceError FrameLoaderClientCd::cannotShowURLError(const WebCore::ResourceRequest&request)
{
    return  ResourceError(String(), InternalErrorCannotShowUrl, request.url(), String());
}

ResourceError FrameLoaderClientCd::interruptedForPolicyChangeError(const WebCore::ResourceRequest&request)
{
    return ResourceError(String(), InternalErrorInterrupted, request.url(), String());
}

ResourceError FrameLoaderClientCd::cannotShowMIMETypeError(const WebCore::ResourceResponse&resp)
{
    return ResourceError(String(), InternalErrorCannotShowMimeType, resp.url(), String());
}

ResourceError FrameLoaderClientCd::fileDoesNotExistError(const WebCore::ResourceResponse&resp)
{
    return ResourceError(String(), InternalErrorFileDoesNotExist, resp.url(), String());
}

ResourceError FrameLoaderClientCd::pluginWillHandleLoadError(const WebCore::ResourceResponse&resp)
{
    return ResourceError(String(), InternalErrorPluginWillHandleLoadError, resp.url(), String());
}

bool FrameLoaderClientCd::shouldFallBack(const ResourceError& error)
{
    return !(error.isCancellation());
}

bool FrameLoaderClientCd::canCachePage() const
{
    return true;
}

Frame* FrameLoaderClientCd::dispatchCreatePage(const NavigationAction&)
{
    notImplemented();
    return 0;
}

void FrameLoaderClientCd::dispatchUnableToImplementPolicy(const ResourceError&)
{
    notImplemented();
}

void FrameLoaderClientCd::setMainDocumentError(DocumentLoader*, const ResourceError& error)
{
    if (!m_pluginView)
        return;

    m_pluginView->didFail(error);
    m_pluginView = 0;
    m_hasSentResponseToPlugin = false;
}

void FrameLoaderClientCd::startDownload(const WebCore::ResourceRequest&req, const String&suggestedName)
{
    //notImplemented();
    LOG(FrameLoader,"FrameLoaderClientCd::startDownload %s ->%s",req.url().string().utf8().data(),suggestedName.utf8().data());
    //m_webView->download(req.url().string().utf8().data(), suggestedName.utf8().data());
}

void FrameLoaderClientCd::updateGlobalHistory()
{
    notImplemented();
}

void FrameLoaderClientCd::updateGlobalHistoryRedirectLinks()
{
    notImplemented();
}

void FrameLoaderClientCd::savePlatformDataToCachedFrame(CachedFrame*)
{
    notImplemented();
}

void FrameLoaderClientCd::transitionToCommittedFromCachedFrame(CachedFrame*)
{
    notImplemented();
}

void FrameLoaderClientCd::transitionToCommittedForNewPage()
{
    Page* page = m_frame->page();
    ASSERT(page);

    WebCore::IntRect rect={0,0,m_webView->getWidth(),m_webView->getHeight()};
    //m_webView->frameRect(rect);
    m_frame->createView(rect.size(), WebCore::Color::white, false);
    LOG(FrameLoader,"FrameLoaderClientCd::transitionToCommittedForNewPage mainframe=%p page=%p frame.view=%p",m_frame,page,m_frame->view());
    /*if (isMainFrame) {
        frameView = FrameView::create(*m_frame, rect.size());
    } else
        frameView = FrameView::create(*m_frame);

    m_frame->setView(frameView);*/

    //if (m_frame->ownerRenderer())
    //    m_frame->ownerRenderer()->setWidget(frameView);
}

void FrameLoaderClientCd::didSaveToPageCache()
{
}

void FrameLoaderClientCd::didRestoreFromPageCache()
{
}

void FrameLoaderClientCd::dispatchDidBecomeFrameset(bool)
{
}

PassRefPtr<WebCore::FrameNetworkingContext> FrameLoaderClientCd::createNetworkingContext()
{
    return FrameNetworkingContextCd::create(m_frame, userAgent(URL()));
}

} // namespace WebKit
